package com.example.demo2.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demo2.mapper.HotelMapper;
import com.example.demo2.model.dtos.QueryDto;
import com.example.demo2.model.pojo.Hotel;
import com.example.demo2.model.pojo.HotelElastic;
import com.example.demo2.model.vos.GroupVo;
import com.example.demo2.model.vos.HotelPageVo;
import com.example.demo2.service.HotelService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class HotelServiceImpl extends ServiceImpl<HotelMapper, Hotel> implements HotelService {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public HotelPageVo homePage(QueryDto queryDto) throws IOException {
        HotelPageVo hotelPageVo = new HotelPageVo();

        SearchRequest searchReq = new SearchRequest("hotel");
        SearchSourceBuilder source = searchReq.source();

        //获取bool条件构建器对象
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        List<QueryBuilder> filter = boolQueryBuilder.filter();

        String keyword = queryDto.getKeyword();
        if (!StringUtils.isBlank(keyword)){
            //设置关键字检索条件
            filter.add(QueryBuilders.matchQuery("all",keyword));
        }

        List<String> cityNames = queryDto.getCityNames();
        if (cityNames!=null && cityNames.size()>0){
            //设置城市名称检索条件
            filter.add(QueryBuilders.termsQuery("city",cityNames.toArray()));
        }

        List<String> brandNames = queryDto.getBrandNames();
        if (brandNames!=null && brandNames.size()>0){
            //设置品牌名称检索条件
            filter.add(QueryBuilders.termsQuery("brand",brandNames.toArray()));
        }

        List<String> starNames = queryDto.getStarNames();
        if (starNames!=null && starNames.size()>0){
            //设置星级名称检索条件
            filter.add(QueryBuilders.termsQuery("starName",starNames.toArray()));
        }

        //设置分页条件
        Integer pageNum = queryDto.getPageNum();
        Integer size = queryDto.getSize();
        source.from((pageNum-1)*size);
        source.size(size);

        source.query(boolQueryBuilder);

        //添加分组聚合条件
        source.aggregation(AggregationBuilders.terms("cityTerms").field("city"));
        source.aggregation(AggregationBuilders.terms("brandTerms").field("brand"));
        source.aggregation(AggregationBuilders.terms("starTerms").field("starName"));

        SearchResponse resp = client.search(searchReq, RequestOptions.DEFAULT);

        //解析resp结果
        //① 获取总记录数
        long total = resp.getHits().getTotalHits().value;
        hotelPageVo.setTotal(total);

        //② 获取列表数据
        SearchHit[] hits = resp.getHits().getHits();
        List<HotelElastic> hotelElastics = Stream.of(hits).map(hit -> {
            String json = hit.getSourceAsString();
            return JSON.parseObject(json, HotelElastic.class);
        }).collect(Collectors.toList());
        hotelPageVo.setList(hotelElastics);

        //③ 解析城市分组信息
        List<GroupVo> cityTerms = parseGroupVo(resp, "cityTerms", GroupVo.GroupType.CITY);
        hotelPageVo.setCityGroup(cityTerms);

        //④ 解析星级分组信息
        List<GroupVo> starTerms = parseGroupVo(resp, "starTerms", GroupVo.GroupType.STAR);
        hotelPageVo.setStarGroup(starTerms);

        //⑤ 解析星级分组信息
        List<GroupVo> brandTerms = parseGroupVo(resp, "brandTerms", GroupVo.GroupType.BRAND);
        hotelPageVo.setBrandGroup(brandTerms);

        return hotelPageVo;
    }

    private List<GroupVo> parseGroupVo(SearchResponse resp, String termsName, GroupVo.GroupType type) {
        ParsedStringTerms cityTerms = resp.getAggregations().get(termsName);
        List<? extends Terms.Bucket> buckets = cityTerms.getBuckets();
        return buckets.stream().map(b -> {
            String name = b.getKeyAsString();
            long count = b.getDocCount();

            GroupVo groupVo = new GroupVo();
            groupVo.setName(name);
            groupVo.setCount((int) count);
            groupVo.setType(type);
            return groupVo;
        }).collect(Collectors.toList());
    }
}
